#include "WidgetTree.h"

#include "PropExtractorViewer.h"

#include <QMenu>
#include <QMap>
#include <QAction>
#include <QFileDialog>
#include <QtGui/QHeaderView>
#include <QtGui/QProgressBar>

// ================================
// Thread
// ================================

TreeThread::TreeThread()
{
	m_Archive = NULL;
}

TreeThread::~TreeThread()
{

}

void TreeThread::run()
{
	if (m_Archive)
	{
		LoadArchiveEntries();
	}

	exit();
}

void TreeThread::SetArchive(pe::PEArchiveRaw* a_Archive)
{
	m_Archive = a_Archive;
}

void TreeThread::LoadArchiveEntries()
{
	QTreeWidgetItem* start = new QTreeWidgetItem();

	for (unsigned int i = 0; i < m_Archive->entries_total; i++)
	{
		QString found_path = QString::fromWCharArray(m_Archive->entries[i].path);
		QStringList found_list = found_path.split("\\", QString::SkipEmptyParts);

		QTreeWidgetItem* curr = start;

		for (QStringList::Iterator it = found_list.begin(); it != found_list.end(); it++)
		{
			bool found = false;
			for (int j = 0; j < curr->childCount(); j++)
			{
				if (curr->child(j)->text(0) == (*it))
				{
					curr = curr->child(j);
					found = true;
					break;
				}
			}

			if (!found)
			{
				TreeItem* curr_item;
				if (it == found_list.end() - 1)
				{
					curr_item = new TreeItem((*it), m_Archive, i, eDataType_Unknown);
				}
				else
				{
					curr_item = new TreeItem((*it), eDataType_Folder);
				}

				emit UpdateBar();

				if (curr == start)
				{
					m_TreeList.push_back(curr_item);
				}

				curr->addChild(curr_item);
				curr = curr_item;
			}
		}		
	}
}

QList<TreeItem*>& TreeThread::GetList()
{
	return m_TreeList;
}

void TreeThread::Clear()
{
	m_TreeList.clear();	

	m_Archive = NULL;
}

// ================================
// Item
// ================================

TreeItem::TreeItem(TreeItemData* a_Data)
{
	m_Data = new TreeItemData;
	memcpy(m_Data, a_Data, sizeof(TreeItemData));

	setText(0, m_Data->text);
}

TreeItem::TreeItem(QString a_Folder, DataType a_Type /*= eDataType_Folder*/) : QTreeWidgetItem(QStringList(a_Folder))
{
	m_Data = new TreeItemData;

	m_Data->text = a_Folder;
	m_Data->type = a_Type;

	m_Data->image = NULL;
	m_Data->archive = NULL;
	m_Data->index = 0;

	setText(0, m_Data->text);
}

TreeItem::TreeItem(QString a_Path, QString a_WorkingDir, DataType a_Type /*= eDataType_Unknown*/) : QTreeWidgetItem(QStringList(a_Path))
{
	m_Data = new TreeItemData;

	m_Data->text = a_Path;
	m_Data->workingdir = a_WorkingDir;
	m_Data->type = a_Type;

	m_Data->image = NULL;
	m_Data->archive = NULL;
	m_Data->index = 0;

	setText(0, m_Data->text);

	SelectType();
}

TreeItem::TreeItem(QString a_Text, pe::PEArchiveRaw* a_ZipHandle, unsigned int a_Index, DataType a_Type /*= eDataType_Unknown*/) : QTreeWidgetItem(QStringList(a_Text))
{
	m_Data = new TreeItemData;

	m_Data->text = a_Text;
	m_Data->workingdir = QString::fromWCharArray(a_ZipHandle->workingdir);
	m_Data->type = a_Type;

	m_Data->image = NULL;
	m_Data->archive = a_ZipHandle;
	m_Data->index = a_Index;

	setText(0, m_Data->text);

	SelectType();
}

TreeItem::~TreeItem()
{

}

void TreeItem::SelectType()
{
	pe::PEStream read;
	GetFileHandle(&read);

	pe::PEFileInfo info;
	if (pe::PropExtractor::Get().ReadFileInfo(info, read) != PE_OK)
	{
		pe::PEStreamClose(&read);
		return;
	}

	if (!strcmp(info.type, "Image"))
	{
		m_Data->type = eDataType_Image;
	}
	else if (!strcmp(info.type, "Model"))
	{
		m_Data->type = eDataType_Model;
	}
	else if (!strcmp(info.type, "Animation"))
	{
		m_Data->type = eDataType_Animation;
	}
	else
	{
		m_Data->type = eDataType_Unknown;
	}

	pe::PEStreamClose(&read);
}

bool TreeItem::GetFileHandle(pe::PEStream* a_Target)
{
	if (m_Data->archive)
	{
		pe::PEArchiveEntryRaw* entry;
		PEArchiveRawGetEntry(&entry, m_Data->archive, m_Data->index);
		PEArchiveRawOpenFile(a_Target, m_Data->archive, entry);

		return true;
	}
	else
	{
		QString path = QString("%1/%2").arg(m_Data->workingdir).arg(m_Data->text);

		wchar_t* path_w;
		QStringToWChar(&path_w, path);

		if (pe::PEStreamOpen(a_Target, path_w, L"rb") != PE_OK)
		{
			pe::PEStreamClose(a_Target);
			return false;
		}

		return true;
	}

	return false;
}

pe::PEImageRaw* TreeItem::GetImageHandle()
{
	/*if (m_Data->image) 
	{ 
		return m_Data->image;
	}

	m_Data->image = new pe::PEImageRaw;

	pe::PEStream read;
	if (!GetFileHandle(&read))
	{
		return false;
	}

	if (pe::AliceSoftReadImage(m_Data->image, &read) == PE_OK)
	{
		return m_Data->image;
	}*/

	return NULL;
}

bool TreeItem::SaveToFile(QString a_Path)
{
	if (m_Data->type == eDataType_Image)
	{
		pe::PEStream read;
		if (!GetFileHandle(&read))
		{
			return false;
		}

		pe::PEImageRaw raw;
		if (pe::PropExtractor::Get().LoadRawImage(raw, read) != PE_OK)
		{
			pe::PEImageRawDelete(&raw);
			return false;
		}

		wchar_t* path_w;
		QStringToWChar(&path_w, a_Path);
		pe::PEImageRawSaveToFile(&raw, path_w);

		pe::PEImageRawDelete(&raw);

		return true;
	}

	return false;
}

// ================================
// Tree
// ================================

WidgetTree::WidgetTree(QWidget* a_Parent /*= 0*/) : QTreeWidget(a_Parent)
{
	m_Zip = false;

	setAcceptDrops(true);

	setColumnCount(1);
	setAutoScroll(true);

	QHeaderView* hdr = header();
	hdr->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
	hdr->setResizeMode(0, QHeaderView::ResizeToContents);
	hdr->setStretchLastSection(false);
	hdr->hide();

	// thread

	m_Thread = new TreeThread();
	connect(m_Thread, SIGNAL(finished()), this, SLOT(LoadFinished()));
	connect(m_Thread, SIGNAL(UpdateBar()), this, SLOT(ItemLoaded()));

	// save to file
	
	QAction* act_save = new QAction("Save to file", this);
	connect(act_save, SIGNAL(triggered()), this, SLOT(SaveFile()));
	m_ActionFile.push_back(act_save);

	QAction* act_save2 = new QAction("Save file uncompressed", this);
	connect(act_save2, SIGNAL(triggered()), this, SLOT(SaveFileUncompressed()));
	m_ActionFile.push_back(act_save2);
	
	// context menu

	connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint &)));
}

WidgetTree::~WidgetTree()
{

}

void WidgetTree::LoadFromDir(QString a_Path, bool a_Relative)
{
	clear();

	m_Zip = false;

	QString path;
	
	if (a_Relative)
	{
		path = QDir::currentPath() + "/" + a_Path;
	}
	else
	{
		path = a_Path;
	}
	m_FileSystem = QDir(path, QString("*.qnt *.pms *.ajp"));

	QFileInfoList list = m_FileSystem.entryInfoList();
	for (QList<QFileInfo>::Iterator i = list.begin(); i != list.end(); i++)
	{
		TreeItem* curr_item = new TreeItem((*i).fileName(), m_FileSystem.path(), eDataType_Unknown);

		addTopLevelItem(curr_item);
	}
}

void WidgetTree::LoadFromZip(QString a_ZipPath, bool a_Relative)
{
	m_Bar = parent()->findChild<QProgressBar*>("barLoading");

	clear();

	m_Zip = true;

	QString path;
	
	if (a_Relative)
	{
		QFileInfo temp(QDir::currentPath() + "/" + a_ZipPath);
		path = temp.canonicalPath() + "/" + temp.fileName();
	}
	else
	{
		path = a_ZipPath;
	}

	wchar_t* path_w;
	QStringToWChar(&path_w, path);
	
	m_Archive = new pe::PEArchiveRaw;
	/*if (pe::AliceSoftOpenArchive(m_Archive, path_w) != PE_OK)
	{
		return;
	}*/

	if (pe::PropExtractor::Get().LoadRawArchive(*m_Archive, path_w) != PE_OK)
	{
		return;
	}

	m_ItemCurrent = 0;
	m_Bar->setValue(0);
	m_Bar->setMaximum(m_Archive->entries_total);
	m_Bar->setDisabled(false);

	// thread

	m_Thread->SetArchive(m_Archive);
	m_Thread->start();
	
	resizeColumnToContents(0);
}

bool WidgetTree::GetSelectedImage(pe::PEImageRaw& a_Target)
{
	bool result = false;

	TreeItem* selected = (TreeItem*)selectedItems()[0];
	if (selected->GetType() == eDataType_Folder) 
	{ 
		return result; 
	}

	pe::PEStream read;

	if (!selected->GetFileHandle(&read))
	{
		return result;
	}

	if (!PropExtractorViewer::Get().IsSafeMode())
	{
		if (pe::PropExtractor::Get().LoadRawImage(a_Target, read) == PE_OK)
		{
			result = true;
		}

		pe::PEStreamClose(&read);

		/*pe::AliceSoftType type;
		AliceSoftCheckType(&type, &read);

		if (type == pe::eAliceSoftType_ImageQNT)
		{
			if (pe::AliceImageQntReadAndDecrypt(&a_Target, &read) == PE_OK)
			{
				return true;
			}
		}
		else if (type == pe::eAliceSoftType_ImagePms)
		{
			if (pe::AliceImagePmsReadAndDecrypt(&a_Target, &read) == PE_OK)
			{
				return true;
			}		
		}
		else if (type == pe::eAliceSoftType_ImageAjp)
		{
			if (pe::AliceImageAjpReadAndDecrypt(&a_Target, &read) == PE_OK)
			{
				return true;
			}		
		}*/
	}

	return result;
}

void WidgetTree::contextMenuEvent(QContextMenuEvent* a_Event)
{
	int i = 0;
}

void WidgetTree::SaveFile()
{
	if (selectedItems().size() == 1)
	{
		TreeItem* selected = (TreeItem*)selectedItems()[0];

		QString savefile;
		if (selected->GetType() == eDataType_Image)
		{
			savefile = QFileDialog::getSaveFileName(this, "Save to file", selected->GetWorkingDir() + selected->text(0), "Images (*.png)");
		}

		if (!savefile.isEmpty()) 
		{ 
			selected->SaveToFile(savefile); 
		}
	}
}


void WidgetTree::SaveFileUncompressed()
{
	TreeItem* selected = (TreeItem*)selectedItems()[0];

	pe::PEArchiveEntryRaw* entry;
	pe::PEArchiveRawGetEntry(&entry, m_Archive, selected->GetData()->index);
	pe::PEArchiveRawSaveCompressedFile(m_Archive, entry);
}


void WidgetTree::ShowContextMenu(const QPoint& a_Pos)
{
	QList<QAction*>* actions;

	QModelIndex ind = indexAt(a_Pos);
	if (ind.isValid())
	{		
		TreeItem* item = (TreeItem*)selectedItems()[0];

		if (item->GetType() == eDataType_Folder)
		{
			actions = &m_ActionDir;
		}
		else
		{
			actions = &m_ActionFile;
		}
	}
	
	if (actions->count() > 0)
	{
		QMenu::exec(*actions, this->mapToGlobal(a_Pos));
	}
}

void AddChild(TreeItem* a_Parent, QTreeWidgetItem* a_Item)
{
	TreeItem* item = new TreeItem(((TreeItem*)a_Item)->GetData());

	a_Parent->addChild(item);

	QList<QTreeWidgetItem*>& list_children = a_Item->takeChildren();
	for (QList<QTreeWidgetItem*>::iterator jt = list_children.begin(); jt != list_children.end(); jt++)
	{
		AddChild((TreeItem*)item, (*jt));
	}
}

void WidgetTree::LoadFinished()
{
	QList<TreeItem*>& list = m_Thread->GetList();

	QTreeWidgetItem* curr = this->invisibleRootItem();

	for (QList<TreeItem*>::iterator it = list.begin(); it != list.end(); it++)
	{
		TreeItem* item = new TreeItem((*it)->GetData());

		QList<QTreeWidgetItem*>& list_children = (*it)->takeChildren();
		for (QList<QTreeWidgetItem*>::iterator jt = list_children.begin(); jt != list_children.end(); jt++)
		{
			AddChild((TreeItem*)item, (*jt));
		}

		addTopLevelItem(item);
	}

	m_Thread->Clear();
}

void WidgetTree::ItemLoaded()
{
	m_Bar->setValue(++m_ItemCurrent);
	if (m_Bar->value() == m_Bar->maximum())
	{
		m_Bar->setValue(0);
		m_Bar->setDisabled(true);
	}
}

void WidgetTree::dropEvent(QDropEvent* a_Event)
{
	int i = 0;
}

void WidgetTree::dragMoveEvent(QDragMoveEvent* a_Event)
{

}

void WidgetTree::dragEnterEvent(QDragEnterEvent* a_Event)
{

}

void WidgetTree::dragLeaveEvent(QDragLeaveEvent* a_Event)
{

}
